#include <OneButton.h>

#include "radio.h"
#include "st7735s.h"

#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
// EC11
#define EC_KEY 13
#define EC_S1 15
#define EC_S2 14

#define I2C_SDA 0  // 18 //0  m
#define I2C_SCL 1  // 19 //1

#elif defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_IDF_TARGET_ESP32S3)
// EC11
#define EC_KEY 2
#define EC_S1 4
#define EC_S2 3

#define I2C_SDA 47
#define I2C_SCL 38
#else  //STM32F103C8T6

#endif

OneButton SW(EC_KEY, true);

Display* display;

enum RADIO_MODULE_TYPE {
  AUTO_FREQ_TYPE = -1,
  FREQ_TYPE,
  BAND_TYPE,
  VOLUME_TYPE,
  AGC_TYPE,
  AVC_TYPE,
  BFO_TYPE,
  STEP_TYPE,
  BW_TYPE,
  pilot_type
};
void freqShow(uint16_t color = ST77XX_GREEN);
void show_volume(uint16_t color = ST77XX_GREEN);
void show_bandWidth(uint16_t color = ST77XX_GREEN);
void show_frequencyStep(uint16_t color = ST77XX_GREEN);
void show_avc(uint16_t color = ST77XX_GREEN);
void show_pilot(uint16_t color = ST77XX_GREEN);
void show_agc(uint16_t color = ST77XX_GREEN);
void show_bfo(uint16_t color = ST77XX_GREEN);
void show_band(uint16_t color = ST77XX_GREEN);
void show_ssb(uint16_t color = ST77XX_GREEN);
void showFrequency(uint16_t freq);
typedef void (*typeFunc)(uint16_t);

typedef struct {
  const char* name;
  uint16_t defaultColor;
  typeFunc func;
} Radio_config;

typedef enum ResourceState {
  IDLE,
  LOCKED
} ResourceState;

ResourceState lock = LOCKED;
ResourceState freqLock = LOCKED;

Radio_config radioConfig[] = {
  { "frequency", ST77XX_GREEN, freqShow },
  { "frequency Name", ST77XX_GREEN, show_band },
  { "volume", ST77XX_GREEN, show_volume },
  { "AGC", ST77XX_GREEN, show_agc },
  { "AVC", ST77XX_GREEN, show_avc },
  { "BFO", ST77XX_GREEN, show_bfo },
  { "frequency step", ST77XX_GREEN, show_frequencyStep },
  { "band width", ST77XX_GREEN, show_bandWidth },
  { "pilot", ST77XX_GREEN, show_ssb }
};

const int lastRadioConfig = (sizeof radioConfig / sizeof(Radio_config)) - 1;
int radioConfigIndex = FREQ_TYPE;
int16_t gIndex = 0;
char currentBand[4] = "\0";
char cpilot[3] = "\0";
char crssi[3] = "\0";
char csnr[3] = "\0";

void sw_init() {
  SW.reset();
  SW.attachClick(click);
  SW.attachDoubleClick(doubleclick);
  SW.attachLongPressStop(longclick);
  SW.setDebounceMs(20);
  SW.setClickMs(200);
  SW.setPressMs(500);
  delay(500);
  attachInterrupt(digitalPinToInterrupt(EC_S1), encoderISR, CHANGE);
}

void click() {
  radioConfigIndex += 1;
  if (radioConfigIndex > lastRadioConfig) {
    radioConfigIndex = 0;
  }
  gIndex = 0;
  Serial.println("radioConfigIndex=>" + String(radioConfigIndex));
  Serial.println("Radio Type Name=>" + String(radioConfig[radioConfigIndex].name));
}

void doubleclick() {
  Serial.print("doubleclick");
  radioConfigIndex -= 1;
  if (0 > radioConfigIndex) {
    radioConfigIndex = lastRadioConfig;
  }
  gIndex = 0;
  /*if (lock == IDLE) {
    lock = LOCKED;
  } else {
    lock = IDLE;
  }*/
}

void longclick() {
  Serial.print("longclick");
  freqLock = IDLE;
  radio_stationUp(showFrequency);
}



#if defined(ESP8266) || (defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_IDF_TARGET_ESP32S3))  // ESP8266 中断调用需要 IRAM_ATTR 加在函数开头
IRAM_ATTR
void encoderISR() {
  int ec_s1 = digitalRead(EC_S1);
  int ec_s2 = digitalRead(EC_S2);
#elif defined(ARDUINO_RASPBERRY_PI_PICO_W)
void encoderISR() {
  PinStatus ec_s1 = digitalRead(EC_S1);
  PinStatus ec_s2 = digitalRead(EC_S2);
#else
void encoderISR() {
  int ec_s1 = digitalRead(EC_S1);
  int ec_s2 = digitalRead(EC_S2);
#endif
  if (ec_s1 == 0 && ec_s2 == 1) {
    gIndex += 1;

  } else if (ec_s1 == 0 && ec_s2 == 0) {
    gIndex -= 1;
  }
  if (freqLock == IDLE) {
    delay(50);
  }
}

void showFrequency(uint16_t freq) {
  radioConfigIndex = AUTO_FREQ_TYPE;
  Serial.println(freq);
}

void freqShow(uint16_t color) {
  if (gIndex != 0) {
    radio_freq(gIndex);
    gIndex = 0;
  }
  uint16_t freq = radio_getCurrentFreq();
  if (radioConfigIndex == FREQ_TYPE) {
    radioConfig[pilot_type].func(radioConfig[pilot_type].defaultColor);
  }
  display->clear(X_LEFT, Y_CENTRE, 125, 30);
  if (freq >= 100 && freq < 1000) {
    display->println(X_RIGHT - 102, Y_CENTRE, 4, color, String(freq).c_str());
  } else if (freq >= 1000 && freq < 10000) {
    display->println(X_RIGHT - 126, Y_CENTRE, 4, color, String(freq).c_str());
  } else if (freq >= 10000) {
    display->println(X_LEFT, Y_CENTRE, 4, color, String(freq).c_str());
  }
}

void show_volume(uint16_t color) {
  uint8_t vol = radio_getVolume() + gIndex;
  if (gIndex != 0) {
    radio_setVolume(vol);
    gIndex = 0;
  }
  if (radioConfigIndex == VOLUME_TYPE) {
    radioConfig[VOLUME_TYPE - 1].func(radioConfig[VOLUME_TYPE - 1].defaultColor);
  }
  display->clear(45, Y_TOP, 30, 20);
  display->println(45, Y_TOP, 2, color, String(radio_getVolume()).c_str());
}

void show_bandWidth(uint16_t color) {
  if (gIndex != 0) {
    radio_setBandWidth(gIndex);
    gIndex = 0;
  }
  if (radioConfigIndex == BW_TYPE) {
    radioConfig[BW_TYPE - 1].func(radioConfig[BW_TYPE - 1].defaultColor);
  }
  display->clear(125, Y_CENTRE, 35, 15);
  display->println(125, Y_CENTRE, 2, color, radio_bandWidth());
}

void show_frequencyStep(uint16_t color) {
  radio_setFrequencyStep(gIndex);
  gIndex = 0;
  if (radioConfigIndex == STEP_TYPE) {
    radioConfig[STEP_TYPE - 1].func(radioConfig[STEP_TYPE - 1].defaultColor);
  }
  display->clear(125, Y_BOTTOM, 50, 20);
  display->println(125, Y_BOTTOM, 2, color, radio_getFrequencyStep());
}

void show_avc(uint16_t color) {
  int8_t gain = radio_avc() + gIndex;
  if (gIndex != 0) {
    radio_setAvc(gain);
    gIndex = 0;
  }
  if (radioConfigIndex == AVC_TYPE) {
    radioConfig[AVC_TYPE - 1].func(radioConfig[AVC_TYPE - 1].defaultColor);
  }

  display->clear(30, Y_BOTTOM, 30, 20);
  display->println(30, Y_BOTTOM, 2, color, String(radio_avc()).c_str());
}

void show_ssb(uint16_t color) {
  if (radio_is_ssb() && !is_all()) {
    if (gIndex != 0) {
      radio_lbub_ssb(gIndex);
      gIndex = 0;
    }
    if (radioConfigIndex == pilot_type) {
      radioConfig[pilot_type - 1].func(radioConfig[pilot_type - 1].defaultColor);
    }
    display->clear(75, Y_TOP, 30, 20);
    display->println(75, Y_TOP, 2, color, radio_pilot());
  } else if (is_all()) {
    if (gIndex != 0) {
      all_am_ssb_switch();
      gIndex = 0;
    }
    if (radioConfigIndex == pilot_type) {
      radioConfig[pilot_type - 1].func(radioConfig[pilot_type - 1].defaultColor);
    }
    display->clear(75, Y_TOP, 30, 20);
    display->println(75, Y_TOP, 2, color, radio_pilot());
  }
}

void show_pilot(uint16_t color) {
  const char* pilot = radio_pilot();
  if (strcmp(cpilot, pilot) != 0) {
    memset(cpilot, '\0', sizeof(cpilot));
    strcpy(cpilot, pilot);
    display->clear(75, Y_TOP, 30, 20);
    display->println(75, Y_TOP, 2, color, pilot);
  }
}
void show_agc(uint16_t color) {
  int8_t idx = radio_agc() + gIndex;
  if (gIndex != 0) {
    radio_setAgc(idx);
    gIndex = 0;
  }
  if (radioConfigIndex == AGC_TYPE) {
    radioConfig[AGC_TYPE - 1].func(radioConfig[AGC_TYPE - 1].defaultColor);
  }
  display->clear(X_LEFT, Y_BOTTOM, 30, 20);
  display->println(X_LEFT, Y_BOTTOM, 2, color, String(radio_agc()).c_str());
}
void show_bfo(uint16_t color) {
  int idx = radio_bfo() + gIndex;
  if (gIndex != 0) {
    radio_setBfo(idx);
    gIndex = 0;
  }
  if (radioConfigIndex == BFO_TYPE) {
    radioConfig[BFO_TYPE - 1].func(radioConfig[BFO_TYPE - 1].defaultColor);
  }
  display->clear(70, Y_BOTTOM, 50, 20);
  display->println(70, Y_BOTTOM, 2, color, String(radio_bfo()).c_str());
}
void show_rssi_snr() {
  radio_getCurrentReceivedSignalQuality();
  char rssi[3] = "\0";
  sprintf(rssi, "%02d", radio_getRssi());
  char snr[3] = "\0";
  sprintf(snr, "%02d", radio_getSnr());
  if (strcmp(rssi, crssi) != 0) {
    memset(crssi, 0, sizeof(crssi));
    strcpy(crssi, rssi);
    display->clear(X_RIGHT - 45, Y_TOP, 30, 20);
    display->println(X_RIGHT - 45, Y_TOP, 2, ST77XX_RED,
                     String(rssi).c_str());
  }
  if (strcmp(snr, csnr) != 0) {
    memset(csnr, 0, sizeof(csnr));
    strcpy(csnr, snr);
    display->clear(X_RIGHT - 15, Y_TOP, 30, 20);
    display->println(X_RIGHT - 15, Y_TOP, 2, ST77XX_RED, String(snr).c_str());
  }
}

void show_band(uint16_t color) {
  Serial.print("gIndex:");
  Serial.println(gIndex);
  const char* freqName = radio_band_selection(gIndex);
  gIndex = 0;
  display->clear(X_LEFT, Y_TOP, 40, 20);
  display->println(X_LEFT, Y_TOP, 2, color, radio_freq_name());
  if (radioConfigIndex != FREQ_TYPE && radioConfigIndex != VOLUME_TYPE) {
    freqShow();
  }
  if (radioConfigIndex != VOLUME_TYPE) {
    show_volume();
    show_bandWidth();
    show_frequencyStep();
    show_avc();
    show_pilot();
    show_agc();
    show_bfo();
    show_rssi_snr();
  }
}

void setup() {
  Serial.begin(9600);
  // while (!Serial)   ;
#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
  Serial.println("ARDUINO_RASPBERRY_PI_PICO_W");
  pinMode(18, INPUT);
  delay(500);
  Wire.setSCL(I2C_SCL);
  Wire.setSDA(I2C_SDA);
  Wire.begin();
#elif defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_IDF_TARGET_ESP32S3)
  Serial.println("CONFIG_IDF_TARGET_ESP32S3");
  // pinMode(12, INPUT);
  pinMode(EC_S1, INPUT);
  pinMode(EC_S2, INPUT);
  delay(500);
  Wire.begin(I2C_SDA, I2C_SCL);
  sw_init();
#endif
  si5351e();
  display = new Display();
  display->clear();
  const char* r = radio_init();
  display->println(X_LEFT, Y_TOP, 2, ST77XX_RED, r);
  delay(1000);
  if (strcmp(r, "Si473X not found!") != 0) {
    radio_band_selection(1);
    display->clear();
    show_band();
    display->println(125, Y_CENTRE + 15, 2, ST77XX_RED, "Khz");
    freqShow(ST77XX_jkl);
  }
}
int currentRadioConfigIndex = -1;
unsigned long previousMillis = 0;
void loop() {
  unsigned long currentMillis = millis();
  if (currentMillis - previousMillis >= 1000) {
    previousMillis = currentMillis;
    if ((currentRadioConfigIndex != radioConfigIndex || gIndex != 0) && radioConfigIndex != AUTO_FREQ_TYPE) {
      currentRadioConfigIndex = radioConfigIndex;
      radioConfig[radioConfigIndex].func(ST77XX_jkl);
    }else if(radioConfigIndex == AUTO_FREQ_TYPE){
      radioConfig[radioConfigIndex + 1].func(ST77XX_jkl);
    }
    gIndex = 0;
    show_pilot();
    show_rssi_snr();
  }
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_IDF_TARGET_ESP32S3)
  SW.tick();  // delay 时间长会导致按键失败
  delay(10);
#else
  delay(1000);
#endif
}

#if defined(ARDUINO_RASPBERRY_PI_PICO_W)
// main
void setup1() {
  sw_init();
}

void loop1() {
  SW.tick();  // delay 时间长会导致按键失败
  delay(10);
}
#endif
